实时渲染中的渲染方程通常写为:
$$
L_0(p,w_0) = L_e(p,w_0) + \int_{\Omega^+} L_i(p,w_i) f_r(p,w_i,w_o) cos\theta_i V(p,w_i) dw_i \tag{3.2}
$$
这里公式中的
这里只考虑点光源或者平行光源。
两趟算法:以点光源为例,第一趟,将摄像机放在点光源的位置,渲染出一张shadow map,其实是depth map,用来记录光源看到的最近的点的深度。第二趟,用实际的观察点渲染场景,对摄像机看到的每一个点
需要注意:shadow map中保存的是世界坐标系下场景中顶点的真实深度(点到光源的真实距离)还是在裁剪空间(视锥体frustum需要经过仿射变换变为正方体形状的裁剪空间)内的z值?进行深度比较时,要保证比较双方的意义是相同的。
平行光源和点光源的区别在于观察空间不同,平行光源是一个长方体,点光源是平截头体。
由于shadow map本身是有分辨率的,所以它每个像素中用一个值表示一片区域的深度值。对地面上的一个点
解决方法:我们可以设定一个bias来抵消上面提到的两个距离的差值,当z + bias < dis 时才判定为遮挡。考虑到在
但设置bias会带来另一个问题:detached shadow。
设置bias后,有可能出现这种情况,即本来判定为遮挡的点,因为bias的存在,被判定为不遮挡。那么当bias较大时,就会出现上图的状况。
还是由于shadow map的每一个像素代表了一块区域,那么当遮挡物离
解决方法:cascaded shadow map等
(试图解决自遮挡和detached shadow的方法,但因耗费太高而没有人用)
这个方法和最基础的Shadow Mapping方法的区别就是,它采用最小深度和次小深度的均值来作为shadow map中的值。因为不采用bias,所以不会出现detached shadow;如果最小深度和次小深度的值相差较大,也会一定程度减少自遮挡(个人理解)。但缺点就是①:需要模型是一个“盒子”类的东西(watertight)②:保存每个像素的最小深度和次小深度,尽管时间复杂度相同为$O(n)$,但这种方法前面的常数部分更大,耗费要更高。
电子竞技不相信眼泪PCF是抗锯齿,反走样的一种技术。
基本思想:对一个像素的某个属性,取它周围多个像素属性的平均值。
在Shadow Mapping中的应用:可用于实现面光源的软阴影的效果
对于一个点
这块filter的区域越大,平均的像素也就越多,可以实现越模糊,越软的阴影。
Percentage-Closer Soft Shadows (nvidia.com)
通过现实中的景象,我们可以观察到阴影在不同位置的软度是不同的。虽然上图有景深导致的模糊,但还是能说明这个问题。
所以需要确定:对于不同位置的着色点
图中
将面光源水平放置,(假设接收物和面光源平行就好,不影响p点接收到的光)。那么公式里的
假设
因为是面光源,所以对于我们要着色的一个点
有一个方法是,让点
至此,就可以完成整个流程:
-
(Blocker search)让点
$p$ 连向面光源的四个顶点,看这个视锥在shadow map上覆盖了多大的区域,在这个区域中计算平均$d_{Blocker}$ 。 -
(Penumbra estimation)用公式(3.4) 计算软阴影范围大小,确定PCF的滤波范围。
-
(Percentage Closer Filting)使用PCF,求出点
$p$ 的阴影深浅程度。
上述过程中,第1步和第3步中,对shadow map中每个像素,需要对它的一个邻域进行某个属性的加权平均,要访问邻域内每个像素的值,那么这种操作的时间耗费就会很高。而VSSM没有访问每一个像素值,而是用一种巧妙的方法得到我们所需要的值。
对于第三步的PCF,我们的操作是,对一个点
如果随机变量
带入到PCF中,意义为,对于一个点,它到光源的距离为
假设均值已知,那么方差可用高数课本里的公式求出:$Var(X) = E(x^2) - E^2(X)$。我们现在只需要知道该邻域的深度值均值,以及深度值平方的均值。
这里的邻域为矩形区域,求一个矩形区域的均值,leetcode上刷的题终于有了用武之地。
前缀和!
这里不再细说了。均值可用前缀和算法求得,对于平方的均值,可以维护一个深度值的平方的map,同样用前缀和得到均值。
虽然这一步也是求一块区域内的深度值均值,但却有一点需要注意,这里求的是矩形区域内blocker的深度值均值,而不是所有深度值的均值。
即在上图的矩形区域中,假设着色点的深度值是7,那么只需要求蓝色数字的均值。来看这样一个公式: $$ \frac{N_1}{N}z_{unocc} + \frac{N_2}{N}z_{occ} = z_{avg} $$
我们想要求得$z_{occ}$,而$\frac{N_1}{N}$可用上面小节提到的切比雪夫不等式近似求得,$\frac{N_2}{N} = 1 - \frac{N_1}{N}$,那么只需要知道$z_{unocc}$就可以了。这里VSSM又做了一个更大胆的假设:认为非遮挡物的深度和当前着色点的深度相同(依据是绝大多数阴影的接收物是个平面),即认为$z_{unocc}=7$,那么除$z_{occ}$的所有变量都是已知的,$z_{occ}$可求。
虽然VSSM耗费大大降低,但目前基本不用这种方法,因为图像降噪的技术非常成熟,可以在采样的PCSS中进行降噪,来达到很好的效果。
切比雪夫不等式
$$
P(x>t) \leq \frac{\sigma^2}{\sigma^2 + (t-\mu)^2}
$$
由于我们由于我们是把切比雪夫不等式当成了等式来使用,那么我们得到的
在VSSM里,切比雪夫不等式来近似求得一个概率,也就是CDF,但这个CDF是不精准的。因此如果能够找到更精确的CDF,就可以得到更精准的结果。
数学概念:矩(moment)是对变量分布和形态特点的一组度量。n阶矩被定义为一变量的n次方与其概率密度函数(PDF)之积的积分。
VSSM中只用到了
图中PCF是书写错误,应该为CDF。可以看到使用前四阶矩得到的CDF就非常精准了。
那么如何用矩得到这样一个CDF,还得看论文:https://jankautz.com/publications/VSSM_PG2010.pdf
这一步的耗费也是很高的。
signed distance function(符号距离函数):对空间中的任意一点,它到一个物体表面有一个最小距离(根据在物体的内外可能区分正负)。
对一个点,它到这个场景的最小距离就是它到每一个物体的最小距离的最小值。空间中每一个点都有这样一个最小距离,这些距离在空间中形成了一个标量场。
应用:
阴影,可以理解为在着色点
对图中圆圈中的点,圆的半径表示它的SDF的值,意味着在以此点为圆心,此半径为球的内部,是没有任何物体的;也就是说在这个球内,没有物体会遮挡住下方的着色点。
和Ray-marching结合,我们可以粗略的估计出着色点被遮挡的程度。如上图,假设从o点射向光源的ray,在点
勾股定理求出
Pros & Cons:
Pros:速度快,质量高
Cons:空间中每个点的SDF需要预计算,存储空间耗费也很高。